#ifndef PRVP_NSShift11Perturbation_HPP_
#define PRVP_NSShift11Perturbation_HPP_

// Framework includes
#include "../OptFrame/NSSeq.hpp"

// Own includes
#include "ProblemInstance.hpp"
#include "Memory.h"
#include "Solution.h"

using namespace std;

class MoveShift11Perturbation: public Move<RepPRVP, MemPRVP>
{
private:
	int p;//period
	int r1, r2;//routes
	int c1, c2;//clients
	int p1, p2;//positions

public:

	using Move<RepPRVP, MemPRVP>::apply; // prevents name hiding
	using Move<RepPRVP, MemPRVP>::canBeApplied; // prevents name hiding

	MoveShift11Perturbation(int _p, int _r1, int _r2, int _c1, int _c2, int _p1, int _p2) :
		p(_p), r1(_r1), r2(_r2), c1(_c1), c2(_c2), p1(_p1), p2(_p2)
	{
	}

	virtual ~MoveShift11Perturbation()
	{
	}

	bool canBeApplied(const RepPRVP& rep)
	{
		return ((p >= 0) && (r1 >= 0) && (r2 >= 0) && (c1 >= 0) && (c2 >= 0) && (p1 >= 0) && (p2 >= 0));
	}

	Move<RepPRVP, MemPRVP>& apply(RepPRVP& rep)
	{
		//pegando os clientes
		int cli1 = rep.at(p).at(r1).at(c1);
		int cli2 = rep.at(p).at(r2).at(c2);

		//removendo os clientes de cada rota
		rep.at(p).at(r1).erase(rep.at(p).at(r1).begin() + c1);
		rep.at(p).at(r2).erase(rep.at(p).at(r2).begin() + c2);

		//verificando se a remoção faz mudar a posição de inserção
		if (c1 < p2)// o c1 estava antes da posição onde será inserido o c2
			p2--;
		if (c2 < p1)// o c2 estava antes da posição onde será inserido o c1
			p1--;

		//fazendo a inserção
		rep.at(p).at(r1).insert(rep.at(p).at(r1).begin() + p2, cli2);
		rep.at(p).at(r2).insert(rep.at(p).at(r2).begin() + p1, cli1);

		return *new MoveShift11Perturbation(p, r1, r2, p2, p1, c2, c1);// SEM MOVIMENTO REVERSO
	}

	virtual bool operator==(const Move<RepPRVP, MemPRVP>& _m) const
	{
		const MoveShift11Perturbation& m = (const MoveShift11Perturbation&) _m;

		return ((p == m.p) && (r1 == m.r1) && (r2 == m.r2) && (c1 == m.c1) && (c2 == m.c2) && (p1 == m.p1) && (p2 == m.p2));

	}

	void print() const
	{
		cout << "MoveShift11Perturbation( ";
		cout << p << " , ";
		cout << r1 << " , ";
		cout << r2 << " , ";
		cout << c1 << " , ";
		cout << c2 << " , ";
		cout << p1 << " , ";
		cout << p2 << " ] , ";
		cout << " )" << endl;
	}
};

class NSShift11Perturbation: public NS<RepPRVP, MemPRVP>
{
private:

public:

	using NS<RepPRVP, MemPRVP>::move; // prevents name hiding

	NSShift11Perturbation()
	{
	}

	virtual ~NSShift11Perturbation()
	{
		//delete movimentos;
	}

	virtual Move<RepPRVP, MemPRVP>& move(const RepPRVP& rep)
	{
		int p = rand() % rep.size();

		if (rep.at(p).size() < 2)
			return *new MoveShift11Perturbation(-1, -1, -1, -1, -1, -1, -1 );

		int r1 = rand() % rep.at(p).size();



		if (rep.at(p).at(r1).size() == 0)
		{
			return *new MoveShift11Perturbation(-1, -1, -1, -1, -1, -1, -1 );
		}

		int r2;
		do
		{
			r2 = rand() % rep.at(p).size();
		}while (r1 == r2);

		if (rep.at(p).at(r2).size() == 0)
		{
			return *new MoveShift11Perturbation(-1, -1, -1, -1, -1, -1, -1 );
		}

		int c1 = rand() % rep.at(p).at(r1).size();
		int c2 = rand() % rep.at(p).at(r2).size();

		int p1 = rand() % (rep.at(p).at(r2).size() + 1);
		int p2 = rand() % (rep.at(p).at(r1).size() + 1);


	return *new MoveShift11Perturbation(p, r1, r2, c1, c2, p1, p2); // return a random move
}

virtual void print()
{
	cout<<"NSShift11Perturbation"<<endl;
}
};

#endif /*PRVP_NSShift11Perturbation_HPP_*/

